﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Quail
{
    /// <summary>
    /// Provides extension method to all objects that implement IWebControlWithRows to get the Rows
    /// </summary>
    public static class WebControlRowExtension
    {
        /// <summary>
        /// Gets an enumeration of rows for the given control
        /// </summary>
        /// <typeparam name="T">The type of control (must be a WebControlRow instance</typeparam>
        /// <param name="control">The control containing rows</param>
        /// <returns>An enumeration of each row</returns>
        public static IEnumerable<T> GetRows<T>(this IWebControlWithRows control) where T : WebControlRow, new()
        {
            return GetRows<T>(control, 0);
        }

        /// <summary>
        /// Gets an enumeration of rows for the given control
        /// </summary>
        /// <typeparam name="T">The type of control (must be a WebControlRow instance</typeparam>
        /// <param name="control">The control containing rows</param>
        /// <param name="startingRow">the starting row</param>
        /// <returns>An enumeration of each row</returns>
        public static IEnumerable<T> GetRows<T>(this IWebControlWithRows control, int startingRow) where T : WebControlRow, new()
        {
            var rc = control.RowCount;
            for (var r = startingRow; r < rc; r++)
            {
                yield return GetRow<T>(control, r);
            }
        }

        /// <summary>
        /// Gets an enumeration of rows for the given control
        /// </summary>
        /// <typeparam name="T">The type of control (must be a WebControlRow instance</typeparam>
        /// <param name="control">The control containing rows</param>
        /// <param name="row">the row</param>
        /// <returns>An enumeration of each row</returns>
        public static T GetRow<T>(this IWebControlWithRows control, int row) where T : WebControlRow, new()
        {
            var hash = control.ControlHashtable;
            string key = null;

            if (hash != null)
            {
                key = string.Format("{0}:{1}:{2}", typeof (T), control.Selector, row);

                var result = hash[key];

                if (result != null)
                    return (T) result;
            }

            var newrow = new T
            {
                ParentControl = (WebControl)control,
                Row = row
            };

            if (hash != null)
            {
                hash[key] = newrow;    
            }

            return newrow;
        }
    }

        /// <summary>
        /// A web control row representing a row in a control with rows
        /// </summary>
    public class WebControlRow : WebControl
    {
        private int _row;

        /// <summary>
        /// Initializes a new instance of the <see cref="WebControlRow"/> class.  The object is not usable until ParentControl and Row properties are set.
        /// </summary>
        public WebControlRow()
        {
            _row = -1;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WebControlRow"/> class.
        /// </summary>
        /// <param name="owner">The owner.</param>
        /// <param name="row">The row.</param>
        public WebControlRow(IWebControlWithRows owner, int row)
            : base((WebControl)owner, owner.GetRowSelector(row))
        {
            _row = row;
        }

        /// <summary>
        /// Gets the parent control as a IWebControlWithRows instance
        /// </summary>
        public IWebControlWithRows ParentControlWithRows
        {
            get
            {
                return (IWebControlWithRows)ParentControl;
            }
        }

        /// <summary>
        /// Gets or sets the row.
        /// </summary>
        public int Row
        {
            get
            {
                return _row;
            }

            set
            {
                if (_row != value)
                {
                    _row = value;
                    MySelector = ParentControlWithRows.GetRowSelector(_row);
                }
            }
        }

        

        /// <summary>
        /// Gets the row selector.
        /// </summary>
        public string RowSelector
        {
            get
            {
                return ParentControlWithRows.GetRowSelector(Row);
            }
        }

        /// <summary>
        /// Gets the text for a specific column
        /// </summary>
        /// <param name="column">the column index</param>
        /// <returns>The text of the cell</returns>
        public string GetColumnText(int column)
        {
            if (ParentControl is WebTable)
                return (ParentControl as WebTable).GetCellText(Row, column);

            return Get<WebControl>(column, "").InnerText;
        }

        /// <summary>
        /// Returns a list of controls that match the jQuery selector for a given column
        /// </summary>
        /// <param name="column">the column index</param>
        /// <param name="selectors">The jQuery selectors to use</param>
        /// <returns>A list of WebControl objects</returns>
        public List<T> GetControls<T>(int column, params string[] selectors)
            where T : WebControl, new()
        {
            var colselector = ParentControlWithRows.GetColumnSelector(column);
            var newselectors = selectors.Select(sel => colselector + " " + sel).ToArray();

            return GetControls((container, sel) => new T
            {
                ParentControl = container,
                MySelector = sel
            },
                               newselectors);
        }

        /// <summary>
        /// Gets a control of a specific type using a specific selector for a given column (may be cached)
        /// </summary>
        /// <typeparam name="T">The type of the control</typeparam>
        /// <param name="column">the column index</param>
        /// <param name="selector">The jQuery selector for the control</param>
        /// <returns>The control</returns>
        public T Get<T>(int column, string selector)
            where T : WebControl, new()
        {
            return Get((Action<T>)null, ParentControlWithRows.GetColumnSelector(column) + " " + selector);
        }

        /// <summary>
        /// Gets the link by text.
        /// </summary>
        /// <param name="column">The column.</param>
        /// <param name="text">The text.</param>
        /// <returns>A web link</returns>
        public WebLink GetLinkByText(int column, string text)
        {
            return Get<WebLink>(column, WebLinkByText.GetWebLinkByTextSelector(text));
        }
    }
}
